#pragma once

#include <linux/compiler.h>
#include <asm/rwonce.h>
#include <asm/processor.h>

// TODO

#ifndef smp_store_mb
#define smp_store_mb(var, value) \
	do                           \
	{                            \
		WRITE_ONCE(var, value);  \
		barrier();               \
	} while (0)
#endif

#ifndef smp_load_acquire
#define smp_load_acquire(p)                   \
	({                                        \
		__typeof__(*p) ___p1 = READ_ONCE(*p); \
		barrier();                            \
		(typeof(*p))___p1;                    \
	})
#endif

#ifndef smp_mb__before_atomic
#define smp_mb__before_atomic()
#endif

#ifndef smp_mb__after_atomic
#define smp_mb__after_atomic() barrier()
#endif

#ifndef smp_wmb
#define smp_wmb() barrier()
#endif

#ifndef smp_rmb
#define smp_rmb()    \
	do               \
	{                \
		__smp_rmb(); \
	} while (0)
#endif

#ifndef __smp_mb
#define __smp_mb() mb()
#endif

#ifndef smp_mb
#define smp_mb()    \
	do              \
	{               \
		__smp_mb(); \
	} while (0)
#endif

/**
 * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency
 *
 * A control dependency provides a LOAD->STORE order, the additional RMB
 * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
 * aka. (load)-ACQUIRE.
 *
 * Architectures that do not do load speculation can have this be barrier().
 */
#ifndef smp_acquire__after_ctrl_dep
#define smp_acquire__after_ctrl_dep() smp_rmb()
#endif

#ifndef smp_store_release
#define smp_store_release(p, v) \
	do                          \
	{                           \
		WRITE_ONCE(*p, v);      \
	} while (0)
#endif

/**
 * smp_cond_load_relaxed() - (Spin) wait for cond with no ordering guarantees
 * @ptr: pointer to the variable to wait on
 * @cond: boolean expression to wait for
 *
 * Equivalent to using READ_ONCE() on the condition variable.
 *
 * Due to C lacking lambda expressions we load the value of *ptr into a
 * pre-named variable @VAL to be used in @cond.
 */
#ifndef smp_cond_load_relaxed
#define smp_cond_load_relaxed(ptr, cond_expr) ({ \
	typeof(ptr) __PTR = (ptr);                   \
	__unqual_scalar_typeof(*ptr) VAL;            \
	for (;;)                                     \
	{                                            \
		VAL = READ_ONCE(*__PTR);                 \
		if (cond_expr)                           \
			break;                               \
		cpu_relax();                             \
	}                                            \
	(typeof(*ptr))VAL;                           \
})
#endif

/**
 * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering
 * @ptr: pointer to the variable to wait on
 * @cond: boolean expression to wait for
 *
 * Equivalent to using smp_load_acquire() on the condition variable but employs
 * the control dependency of the wait to reduce the barrier on many platforms.
 */
#ifndef smp_cond_load_acquire
#define smp_cond_load_acquire(ptr, cond_expr) ({  \
	__unqual_scalar_typeof(*ptr) _val;            \
	_val = smp_cond_load_relaxed(ptr, cond_expr); \
	smp_acquire__after_ctrl_dep();                \
	(typeof(*ptr))_val;                           \
})
#endif

/**
 * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency
 *
 * A control dependency provides a LOAD->STORE order, the additional RMB
 * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
 * aka. (load)-ACQUIRE.
 *
 * Architectures that do not do load speculation can have this be barrier().
 */
#ifndef smp_acquire__after_ctrl_dep
#define smp_acquire__after_ctrl_dep() smp_rmb()
#endif
